package com.pai4j.jianlipai.controller.jianlibot;

import com.pai4j.common.bean.PAIPageResponseBeanUtil;
import com.pai4j.common.bean.PAIResponseBean;
import com.pai4j.common.bean.PAIResponseBeanUtil;
import com.pai4j.common.enums.jianlibot.ResumeTemplateEnum;
import com.pai4j.common.exception.BusinessException;
import com.pai4j.common.helper.SessionHelper;
import com.pai4j.common.util.ThreadPoolExecutorAIUtil;
import com.pai4j.domain.dto.jianlipai.ResumeDetail;
import com.pai4j.domain.dto.llm.ChatCompletionMessage;
import com.pai4j.domain.dto.llm.ChatMessageRole;
import com.pai4j.domain.vo.request.jianlipai.AICreateResumeVO;
import com.pai4j.domain.vo.request.jianlipai.CreateResumeVO;
import com.pai4j.domain.vo.request.jianlipai.OnePaperSaveRequestVO;
import com.pai4j.domain.vo.response.jianlipai.OnePaperFileVO;
import com.pai4j.domain.vo.response.jianlipai.ResumeBaseVO;
import com.pai4j.domain.vo.response.jianlipai.ResumeDetailVO;
import com.pai4j.domain.vo.response.jianlipai.ResumeManageVO;
import com.pai4j.common.config.annotation.RequestPermission;
import com.pai4j.jianlipai.service.MoonshotAIService;
import com.pai4j.jianlipai.service.jianlibot.AiGenResumeService;
import com.pai4j.jianlipai.service.jianlibot.JianLiPaiService;
import com.pai4j.log.annotation.OperationLog;
import com.pai4j.remote.jianlipai.JianLiPaiClient;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 简历控制器
 *
 * @author: CYM-pai
 * @date: 2025/05/06 14:14
 **/
@RestController
public class JianLiPaiController implements JianLiPaiClient {

    @Resource
    private MoonshotAIService moonshotAIService;
    @Resource
    private JianLiPaiService jianLiPaiService;
    @Resource
    private AiGenResumeService aiGenResumeService;

    private final ConcurrentHashMap<String, SseEmitter> users = new ConcurrentHashMap<>();

    
    /**
     * 后台全部的简历列表
     *
     * @author: CYM-pai
     * @date: 2025/05/07 10:44
     **/
    @RequestPermission
    @Override
    public PAIPageResponseBeanUtil<List<ResumeManageVO>> getResumeList(@RequestParam(value = "pageNo", required = false, defaultValue = "1") Integer pageNo,
                                                                       @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize) {

        return jianLiPaiService.getResumeList(pageNo, pageSize);
    }

    /**
     *创建简历
     *
     * @author: CYM-pai
     * @date: 2025/05/07 10:45
     **/
    @Override
    @OperationLog(
        module = "简历管理",
        operation = "创建简历",
        description = "用户创建新简历",
        recordParams = true
    )
    public PAIResponseBean<String> createResume(@RequestBody @Valid CreateResumeVO createResumeVO) {
        ResumeTemplateEnum.validate(createResumeVO.getTemplateCode());
        String userId = SessionHelper.getCurrentUserId();
        createResumeVO.setUserId(userId);
        String id = jianLiPaiService.createResume(createResumeVO);
        return PAIResponseBeanUtil.success(id);
    }
    /**
     * AI生成简历
     *
     * @author: CYM-pai
     * @date: 2025/05/06 15:35
     **/
    @Override
    @OperationLog(
        module = "简历管理",
        operation = "AI生成简历",
        description = "用户使用AI生成简历",
        recordParams = true
    )
    public PAIResponseBean<ResumeDetail> aiGen(@RequestBody @Valid AICreateResumeVO aiCreateResumeVO) {
        String userId = SessionHelper.getCurrentUserId();
        aiCreateResumeVO.setUserId(userId);
        ResumeDetail resumeDetail = aiGenResumeService.aiGenResume(aiCreateResumeVO);
        return PAIResponseBeanUtil.success(resumeDetail);
    }
    
    /**
     * 删除简历
     *
     * @author: CYM-pai
     * @date: 2025/05/07 10:55
     **/
    @Override
    @OperationLog(
        module = "简历管理",
        operation = "删除简历",
        description = "用户删除简历",
        recordParams = true
    )
    public PAIResponseBean<Boolean> deleteResume(@PathVariable String resumeId) {
        String userId = SessionHelper.getCurrentUserId();
        jianLiPaiService.deleteResume(userId, resumeId);
        return PAIResponseBeanUtil.success(true);
    }

    /**
     * 获取用户简历列表
     *
     * @author: CYM-pai
     * @date: 2025/05/07 10:50
     **/
    @Override
    public PAIResponseBean<ResumeBaseVO> listUserResumes() {
        String userId = SessionHelper.getCurrentUserId();
        if (StringUtils.isBlank(userId)) {
            return PAIResponseBeanUtil.success(new ArrayList<>());
        }
        List<ResumeBaseVO> resumeBaseVOList = jianLiPaiService.getUserResumeListCache(userId);
        return PAIResponseBeanUtil.success(resumeBaseVOList);
    }
    /**
     * 保存简历: 对应前端的导出pdf
     *
     * @param saveRequest
     * @return
     */
    @Override
    @OperationLog(
        module = "简历管理",
        operation = "保存简历",
        description = "用户保存简历为PDF",
        recordParams = true
    )
    public PAIResponseBean<String> save(@RequestBody OnePaperSaveRequestVO saveRequest) {
        saveRequest.validate();
        saveRequest.setUserId(SessionHelper.getCurrentUserId());
        String id = jianLiPaiService.save(saveRequest);
        return PAIResponseBeanUtil.success(id);
    }

    /**
     * 获取简历文件名
     *
     * @param id
     * @return
     */
   @Override
    public PAIResponseBean<OnePaperFileVO> filename(@PathVariable String id) {
        String userId = SessionHelper.getCurrentUserId();
        ResumeBaseVO resumeBase = jianLiPaiService.getResumeBaseFromCache(id);
        Assert.isTrue(resumeBase != null, "未查找到简历信息！");
        Assert.isTrue(resumeBase.getUserId().equals(userId), "无权限！");
        return PAIResponseBeanUtil.success(new OnePaperFileVO(resumeBase.getName(), resumeBase.getFileSize()));
    }

    
    /**
     * 获取简历详情
     *
     * @param id
     * @param view
     * @return
     */
    @Override
    public PAIResponseBean<OnePaperSaveRequestVO> detail(@PathVariable String id,
                                                         @RequestParam(value = "view", required = false, defaultValue = "false") Boolean view) {
        String userId = SessionHelper.getCurrentUserId();
        if (!ObjectUtils.equals(view, true) && StringUtils.isBlank(userId)) {
            throw new BusinessException("未登录！");
        }
        ResumeDetailVO resumeDetail = jianLiPaiService.getResumeDetailFromCache(id);
        Assert.isTrue(resumeDetail != null, "未查找到简历信息！");
        if (!ObjectUtils.equals(view, true)) {
            Assert.isTrue(resumeDetail.getUserId().equals(userId), "无权限！");
        }
        return PAIResponseBeanUtil.success(resumeDetail);
    }
    
    /**
     * 简历摘要
     *
     * @author: CYM-pai
     * @date: 2025/05/07 10:50
     **/
    @Override
    public PAIResponseBean summary(@PathVariable String id) {
        String userId = SessionHelper.getCurrentUserId();
        SseEmitter emitter = users.get(userId);
        jianLiPaiService.clearContextMessage(userId);
        ResumeDetailVO detail = jianLiPaiService.getResumeDetailFromCache(id);
        Assert.isTrue(detail != null, "未查找到简历信息！");
        Assert.isTrue(detail.getUserId().equals(userId), "无权限！");
        jianLiPaiService.addContextMessage(userId, new ChatCompletionMessage(ChatMessageRole.SYSTEM.value(),
                "请记住你是由程序员pai出品的 JianLiPai AI（一个专业的简历智能助手），同时你也是一位资深面试官，你更了解程序员、测试人员、产品经历、运营人员的职业内容，主要指责帮助用户修改简历和指导面试。你会为用户提供安全，有帮助，准确的回答。同时，你会拒绝一些涉及恐怖主义，种族歧视，黄色暴力等问题的回答。JianLiPai AI 为专有名词，不可翻译成其他语言。"));
        final List<ChatCompletionMessage> messages = jianLiPaiService.addContextMessage(userId,
                new ChatCompletionMessage(ChatMessageRole.USER.value(),
                String.format("请对我的简历内容，1、进行一句话100字左右的总结；2、专业且详细的内容纠错(尽可能一次告诉我简历中的所有问题)，并针对问题提出有效的修改建议，以(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)……序号列表的方式返回给我；3、根据人岗匹配原则，推荐给我3家最适合我的公司及岗位信息，不一定非要推荐大厂；最后给个综合打分。\n我的简历内容信息如下:\n %s"
                        , detail.getResumeContent())));
        if (emitter != null) {
            ThreadPoolExecutorAIUtil.execute(() -> {
                try {
                    moonshotAIService.chat(emitter, messages);
                } catch (Exception e) {
                    emitter.completeWithError(e);
                }
            });
        }
        return PAIResponseBeanUtil.success("success");
    }
    
    /**
     * 处理发送消息请求的方法
     * 该方法首先检查传入的消息是否为空，然后获取当前用户的ID，并根据用户ID获取对应的SseEmitter对象
     * 接着，它会获取用户聊天的上下文消息，如果上下文为空，则添加系统默认的上下文消息
     * 最后，将用户发送的消息添加到上下文中，并尝试通过SseEmitter对象发送消息
     *
     * @param message 用户发送的消息内容
     * @return 返回一个表示操作结果的PAIResponseBean对象
     */
    @Override
    public PAIResponseBean sendMessage(@RequestBody String message) {
    // 检查消息是否为空
    if (StringUtils.isBlank(message)) {
        return PAIResponseBeanUtil.success("message is blank!");
    }
    // 获取当前用户ID
    String userId = SessionHelper.getCurrentUserId();
    // 获取用户的SseEmitter对象
    SseEmitter emitter = users.get(userId);
    // 获取用户聊天的上下文消息
    List<ChatCompletionMessage> context = jianLiPaiService.getContextMessage(userId);
    // 如果上下文消息为空，则添加系统默认的上下文消息
    if (CollectionUtils.isEmpty(context)) {
        jianLiPaiService.addContextMessage(userId, new ChatCompletionMessage(ChatMessageRole.SYSTEM.value(),
                "请记住你是由程序员pai出品的 JianLiPai AI（一个多功能的简历智能助手），同时你也是一位资深面试官，你更了解程序员、测试人员、产品经历、运营人员的职业内容，主要指责帮助用户修改简历和指导面试。你会为用户提供安全，有帮助，准确的回答。同时，你会拒绝一些涉及恐怖主义，种族歧视，黄色暴力等问题的回答。JianLiPai AI 为专有名词，不可翻译成其他语言。"));
    }
    // 将用户发送的消息添加到上下文中
    final List<ChatCompletionMessage> messages =
            jianLiPaiService.addContextMessage(userId, new ChatCompletionMessage(ChatMessageRole.USER.value(), message));
    // 如果emitter不为空，则在线程池中执行发送消息的操作
    if (emitter != null) {
        ThreadPoolExecutorAIUtil.execute(() -> {
            try {
                // 调用聊天服务，通过emitter发送消息
                moonshotAIService.chat(emitter, messages);
            } catch (Exception e) {
                // 如果发送过程中出现异常，完成发送并抛出异常
                emitter.completeWithError(e);
            }
        });
    }
    // 返回成功响应
    return PAIResponseBeanUtil.success("success");
}

   /**
 * 添加系统消息接口
 * 该方法用于接收客户端发送的消息，并将其作为系统消息添加到对话上下文中
 * 主要用于在对话过程中，将一些特定的信息作为系统消息插入
 *
 * @param message 从客户端接收到的消息，用于创建系统消息
 * @return 返回一个表示操作成功的PAIResponseBean对象
 */
    @Override
    public PAIResponseBean addSystemMessage(@RequestBody String message) {
    String userId = SessionHelper.getCurrentUserId();
    jianLiPaiService.addContextMessage(userId, new ChatCompletionMessage(ChatMessageRole.SYSTEM.value(), message));
    return PAIResponseBeanUtil.success("success");
}
    
    /**
     * 停止聊天流接口
     * 当用户结束与AI的聊天时调用此方法，以关闭对应的SseEmitter流
     * 防止资源泄露和不必要的消息推送
     *
     * @return 返回一个表示操作成功的PAIResponseBean对象
     */
    @Override
    public PAIResponseBean stopChat() {
        String userId = SessionHelper.getCurrentUserId();
        SseEmitter emitter = users.get(userId);
        if (emitter != null) {
            emitter.complete();
        }
        return PAIResponseBeanUtil.success();
    }
    
    /**
     * 创建聊天流接口
     * 建立与客户端的长连接，用于实时推送AI的回复消息
     * 只有当用户登录时，才能创建有效的聊天流
     *
     * @param request HTTP请求对象，用于获取用户信息
     * @return 返回一个SseEmitter对象，用于与客户端建立Stream流连接
     * @throws BusinessException 如果用户未登录，则抛出业务异常
     */
    @Override
    public SseEmitter channel(HttpServletRequest request) {
        SseEmitter emitter = new SseEmitter(120_000L);
        try {
            String userId = SessionHelper.getCurrentUserId();
            if (StringUtils.isBlank(userId)) {
                emitter.send(SseEmitter.event().name("error").data("用户未登录"));
                emitter.complete();
                return emitter;
            }
            // ✅ 立即发送一条初始化事件，避免超时
            emitter.send(SseEmitter.event().name("connected").data("SSE连接已建立"));
            
            users.put(userId, emitter);
        } catch (Exception e) {
            emitter.completeWithError(e);
        }
        return emitter;
    }
}
